package com.shuan;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;

/**
 * 
 * @author hehuosheng
 * @date 2025/8/31
 **/
//@Mojo(name = "encrypt", defaultPhase = LifecyclePhase.PROCESS_CLASSES) // 绑定到 process-classes 阶段
@Mojo(name = "encrypt",
    defaultPhase = LifecyclePhase.PACKAGE,
    requiresProject = true,
    threadSafe = true,
    executionStrategy = "",
    requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME
)
public class EncryptionMojo extends AbstractMojo {
    // Maven 项目对象（用于获取路径）
    @Parameter(defaultValue = "${project}", required = true, readonly = true)
    private MavenProject project;

    // 待加密的类全限定名
    @Parameter(required = true, property = "encrypt.classes")
    private List<String> classesToEncrypt;

    // 加密密钥
    @Parameter(required = true, property = "encrypt.key")
    private String encryptionKey;

    // 加密后类文件的临时输出目录（默认 target/encrypted-classes）
    @Parameter(defaultValue = "${project.build.directory}/encrypted-classes", property = "encrypt.outputDir")
    private File encryptedOutputDir;

    @Override
    public void execute() throws MojoExecutionException {
        getLog().info("开始执行类加密...");
        getLog().info("待加密类：" + classesToEncrypt);
        getLog().info("加密密钥：" + encryptionKey);
        getLog().info("加密输出目录：" + encryptedOutputDir);

        try {
            // 1. 加密类并输出到临时目录（原有逻辑）
            encryptClassesToTempDir();

            // 2. 将加密后的类复制到 target/classes（覆盖原始类）
            copyEncryptedClassesToOutputDir();

            getLog().info("类加密并替换完成！");
        } catch (Exception e) {
            throw new MojoExecutionException("加密或替换类失败", e);
        }
    }

    /**
     * 加密类并输出到临时目录（原有逻辑）
     */
    private void encryptClassesToTempDir() throws Exception {
        // 确保临时输出目录存在
        if (!encryptedOutputDir.exists() && !encryptedOutputDir.mkdirs()) {
            throw new IOException("无法创建加密输出目录：" + encryptedOutputDir);
        }

        for (String className : classesToEncrypt) {
            // 将全限定类名转换为文件路径（如 "com.shuan.modules.service.impl.UserServiceImpl" → "com/shuan/modules/service/impl/UserServiceImpl.class"）
            String classFileName = className.replace('.', File.separatorChar) + ".class";
            Path inputPath = Paths.get(project.getBuild().getOutputDirectory(), classFileName);
            Path encryptedPath = encryptedOutputDir.toPath().resolve(classFileName);

            // 读取原始类字节码
            byte[] originalBytes;
            if (!Files.exists(inputPath)) {
                throw new FileNotFoundException("原始类文件不存在：" + inputPath);
            }
            originalBytes = Files.readAllBytes(inputPath);

            // 加密字节码（调用你的 Encryptor 工具类）
            byte[] encryptedBytes = Encryptor.encrypt(originalBytes, encryptionKey.getBytes());

            // 写入临时加密目录
            Files.createDirectories(encryptedPath.getParent());
            Files.write(encryptedPath, encryptedBytes);
            getLog().info("加密类成功：" + className);
        }
    }

    /**
     * 将加密后的类从临时目录复制到 target/classes（覆盖原始类）
     */
    private void copyEncryptedClassesToOutputDir() throws IOException {
        Path outputDirPath = Paths.get(project.getBuild().getOutputDirectory());
        getLog().info("将加密类复制到：" + outputDirPath);

        // 遍历临时加密目录下的所有 .class 文件
        Files.walkFileTree(encryptedOutputDir.toPath(), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path source, BasicFileAttributes attrs) throws IOException {
                //attrs.isRegularFile()
                if (attrs.isRegularFile() && source.toString().endsWith(".class")) {
                    // 计算目标路径（相对于临时目录的相对路径，拼接到 outputDirPath）
                    Path relativePath = encryptedOutputDir.toPath().relativize(source);
                    Path targetPath = outputDirPath.resolve(relativePath);

                    // 确保目标目录存在
                    Files.createDirectories(targetPath.getParent());

                    // 复制并覆盖原始文件
                    Files.copy(source, targetPath, StandardCopyOption.REPLACE_EXISTING);
                    getLog().info("替换原始类：" + targetPath);
                }
                return FileVisitResult.CONTINUE;
            }
        });
    }
}
